<template>
  <div
    ref="basicTableRef"
    :class="{
      'table-full-screen': isFullscreen,
    }"
  >
    <div class="table-toolbar">
      <!--顶部左侧区域-->
      <div class="flex items-center table-toolbar-left">
        <template v-if="leftTitle">
          <div class="table-toolbar-left-title">
            {{ leftTitle }}
            <a-tooltip v-if="leftTitleTooltip">
              <template #content>{{ leftTitleTooltip }}</template>
              <span class="ml-1 text-gray-400 cursor-pointer">
                <QuestionCircleOutlined class="arco-icon" />
              </span>
            </a-tooltip>
          </div>
        </template>
        <slot name="tableTitle"></slot>
      </div>

      <div class="flex items-center table-toolbar-right">
        <!--顶部右侧区域-->
        <slot name="toolbar"></slot>

        <template v-if="isTableSetting">
          <!--表格斑马纹-->
          <a-tooltip v-if="isShowTablestripe" mini>
            <template #content>表格斑马纹</template>
            <div class="table-toolbar-right-icon">
              <a-switch v-model="stripe" checked-children="开" un-checked-children="关" />
            </div>
          </a-tooltip>

          <a-divider direction="vertical" />
          <!--刷新-->
          <a-tooltip v-if="isShowTableRedo" mini>
            <template #content>刷新</template>
            <div
              class="table-toolbar-right-icon"
              :class="{ 'ml-0': isShowTablestripe }"
              @click="reload"
            >
              <ReloadOutlined class="arco-icon" />
            </div>
          </a-tooltip>

          <!--密度-->
          <a-tooltip v-if="isShowTableSize" mini>
            <template #content>密度</template>
            <div class="table-toolbar-right-icon">
              <a-dropdown v-model="tableSize" @select="densitySelect">
                <ColumnHeightOutlined class="arco-icon" />
                <template #content>
                  <a-doption v-for="item in densityOptions" :key="item.key" :value="item.key">{{
                    item.label
                  }}</a-doption>
                </template>
              </a-dropdown>
            </div>
          </a-tooltip>

          <!--表格设置单独抽离成组件-->
          <ColumnSetting
            v-if="isShowTableSetting"
            @columns-change="columnsChange"
            :tableSetting="props.tableSetting"
          />

          <!--全屏-->
          <a-tooltip v-if="isShowTableFullscreen" mini>
            <template #content>{{ isFullscreen ? '还原' : '全屏' }}</template>
            <div class="table-toolbar-right-icon" @click="toggleTableFullScreen">
              <FullscreenExitOutlined v-if="isFullscreen" class="arco-icon" />
              <FullscreenOutlined v-else class="arco-icon" />
            </div>
          </a-tooltip>
        </template>
      </div>
    </div>
    <div class="s-table" v-if="isShowTable">
      <a-table
        ref="tableElRef"
        v-model:selectedKeys="checkedRowKeys"
        v-bind="getBindValues"
        :pagination="pagination"
        @page-change="handlePageChange"
        @page-size-change="handlePageSizeChange"
        @select="handleSelect"
        @select-all="handleSelectAll"
        class="basicTable"
      >
        <template v-for="item in Object.keys($slots)" :key="item" #[item]="data">
          <slot v-bind="data" :name="item"></slot>
        </template>
      </a-table>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { ref, unref, toRaw, computed, onMounted, nextTick, useAttrs } from 'vue';

  import { createTableContext } from './hooks/useTableContext';
  import ColumnSetting from './components/settings/ColumnSetting.vue';

  import { useLoading } from './hooks/useLoading';
  import { useColumns } from './hooks/useColumns';
  import { useDataSource } from './hooks/useDataSource';
  import { usePagination } from './hooks/usePagination';

  import { basicProps } from './props';
  import { BasicTableProps } from './types/table';

  import { getViewportOffset } from '@/utils/domUtils';
  import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn';
  import { isBoolean } from '@/utils/is';
  import { useFullscreen } from '@vueuse/core';

  import {
    ReloadOutlined,
    ColumnHeightOutlined,
    QuestionCircleOutlined,
    FullscreenExitOutlined,
    FullscreenOutlined,
  } from '@vicons/antd';

  const props = defineProps({
    ...basicProps,
  });

  const emit = defineEmits([
    'fetch-success',
    'fetch-error',
    'update:checked-row-keys',
    'edit-end',
    'edit-cancel',
    'edit-row-end',
    'edit-change',
    'select',
    'select-all',
    'columns-change',
  ]);

  const densityOptions = [
    {
      label: '迷你',
      key: 'mini',
    },
    {
      label: '紧凑',
      key: 'small',
    },
    {
      label: '中间',
      key: 'middle',
    },
    {
      label: '默认',
      key: 'large',
    },
  ];

  const stripe = ref(false);
  const isShowTable = ref(true);
  const deviceHeight = ref<Number | String>('auto');
  const tableElRef = ref(null);
  const wrapRef = ref(null);
  const basicTableRef = ref<HTMLElement | null>(null);
  const checkedRowKeys = ref<string[] | number[]>([]);

  const tableData = ref<Recordable[]>([]);
  const innerPropsRef = ref<Partial<BasicTableProps>>();

  const { isFullscreen, toggle } = useFullscreen(basicTableRef);

  const getProps: any = computed(() => {
    return { ...props, ...unref(innerPropsRef) };
  });

  const { getLoading, setLoading } = useLoading(getProps);

  const { getPaginationInfo, setPagination } = usePagination(getProps);

  const {
    getDataSourceRef,
    getRowKey,
    reload,
    restReload,
    setTableData,
    getDataSource,
    updateTableData,
    tableChange,
  } = useDataSource(
    getProps,
    {
      getPaginationInfo,
      setPagination,
      tableData,
      setLoading,
    },
    emit,
  );

  const { getPageColumns, setColumns, getColumns, getCacheColumns, setCacheColumnsField } =
    useColumns(getProps);

  const tableSize = ref(unref(getProps as any).size || 'medium');

  //点击行选择器时触发
  function handleSelect(rowKeys, rowKey, record) {
    emit('select', rowKeys, rowKey, record);
  }

  //点击全选选择器时触发
  function handleSelectAll(checked) {
    emit('select-all', checked);
  }

  //清空行
  function restCheckedRowKeys() {
    checkedRowKeys.value = [];
    //需要emit出去，不然监听不到
    emit('select', checkedRowKeys);
  }

  //分页发生改变
  function handlePageChange(page) {
    tableChange({
      current: page,
    });
  }

  //分页数量改变
  async function handlePageSizeChange(pageSize) {
    !getProps.value.isKeepRowKeys && (await restCheckedRowKeys());
    tableChange({
      pageSize,
    });
  }

  //密度切换
  function densitySelect(key) {
    tableSize.value = key;
  }

  //获取表格大小
  const getTableSize = computed(() => tableSize.value);

  //获取斑马纹
  const getstripe = computed(() => stripe.value);

  //表格设置工具
  const isTableSetting = computed(() => getProps.value.showTableSetting);

  //是否显示刷新按钮
  const isShowTableRedo = computed(() => getProps.value.tableSetting?.redo ?? true);

  //斑马纹
  const isShowTablestripe = computed(() => getProps.value.tableSetting?.stripe ?? true);

  //是否显示尺寸调整按钮
  const isShowTableSize = computed(() => getProps.value.tableSetting?.size ?? true);

  //是否显示字段调整按钮
  const isShowTableSetting = computed(() => getProps.value.tableSetting?.setting ?? true);

  //是否显示表格全屏按钮
  const isShowTableFullscreen = computed(() => getProps.value.tableSetting?.fullscreen ?? true);

  //计算高度
  const getDeviceHeight = computed(() => {
    const tableData = unref(getDataSourceRef);
    if (deviceHeight.value === 'auto') return 'auto';
    return tableData.length ? unref(deviceHeight) : 'auto';
  });

  const getTableScroll = computed(() => {
    const { scroll, canResize } = getProps.value;
    return {
      x: '100%',
      y: canResize ? getDeviceHeight.value : null,
      maxHeight: getDeviceHeight.value,
      ...(scroll || {}),
    };
  });

  //组装表格信息
  const getBindValues = computed(() => {
    const tableData = unref(getDataSourceRef);
    return {
      ...unref(getProps),
      loading: unref(getLoading),
      columns: toRaw(unref(getPageColumns)),
      rowKey: unref(getRowKey),
      data: tableData,
      size: unref(getTableSize),
      stripe: unref(getstripe),
      scroll: unref(getTableScroll),
      rowClassName:
        stripe.value && !unref(getProps).rowClassName
          ? (_record, index) => (index % 2 === 1 ? 'table-stripe' : null)
          : null,
    };
  });

  //columns 列变动
  function columnsChange(columns) {
    emit('columns-change', columns);
  }

  //返回表格 ref 实例
  function getTableRef() {
    return tableElRef.value;
  }

  //表格全屏
  function toggleTableFullScreen() {
    toggle();
  }

  //重新计算表格高度
  function redoHeight() {
    computeTableHeight();
  }

  //获取分页信息
  const pagination = computed(() => toRaw(unref(getPaginationInfo)));

  function setProps(props: Partial<BasicTableProps>) {
    innerPropsRef.value = { ...unref(innerPropsRef), ...props };
  }

  const tableAction = {
    reload,
    restReload,
    redoHeight,
    setColumns,
    setLoading,
    setProps,
    setTableData,
    getTableRef,
    getDataSource,
    getColumns,
    getPageColumns,
    getCacheColumns,
    setCacheColumnsField,
    updateTableData,
    emit,
  };

  createTableContext({ ...tableAction, wrapRef, getBindValues, isShowTable });

  const getCanResize = computed(() => {
    const { canResize } = unref(getProps);
    return canResize;
  });

  async function computeTableHeight() {
    const { pagination } = unref(getProps);
    if (!unref(getCanResize)) return;
    await nextTick();
    // @ts-ignore
    const tableEl: any = unref(basicTableRef);
    if (!tableEl) return;
    const headerH = 64;
    let paginationH = 0;
    let marginH = 54;
    const { bottomIncludeBody } = getViewportOffset(tableEl);
    if (!bottomIncludeBody) return;

    if (!isBoolean(pagination)) {
      paginationH = 44;
    }
    let height =
      bottomIncludeBody - (headerH + paginationH + marginH + (props.resizeHeightOffset || 0));
    const maxHeight = props.maxHeight;
    height = maxHeight && maxHeight < height ? maxHeight : height;
    deviceHeight.value = height;
  }

  useWindowSizeFn(computeTableHeight, 280);

  onMounted(() => {
    nextTick(() => {
      computeTableHeight();
    });
  });

  //导出方法到外部使用
  defineExpose({
    ...tableAction,
  });
</script>
<style lang="less" scoped>
  .table-toolbar {
    display: flex;
    justify-content: space-between;
    padding: 0 0 16px 0;

    &-left {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      flex: 1;

      &-title {
        display: flex;
        align-items: center;
        justify-content: flex-start;
        font-size: 16px;
        font-weight: 600;
      }
    }

    &-right {
      display: flex;
      justify-content: flex-end;
      flex: 1;

      &-icon {
        margin-left: 12px;
        font-size: 16px;
        cursor: pointer;
        //color: var(--text-color);

        //:hover {
        //  color: v-bind(getAppTheme);
        //}
      }
      .ml-0 {
        margin-left: 0;
      }
    }
  }

  .table-toolbar-inner-popover-title {
    padding: 2px 0;
  }

  .s-table :deep(.ant-table-pagination.ant-pagination) {
    float: none;
    text-align: center;
    margin-bottom: 0;
  }

  .table-full-screen {
    background: #fff;
    padding: 20px;
  }

  .dark {
    .table-full-screen {
      background: #151515;
    }
  }

  .basicTable :deep(.table-stripe) td {
    background-color: #fafafa;
  }
</style>
